a tool for shared writing and social publishing
1import { NextResponse } from "next/server";
2import { DidResolver } from "@atproto/identity";
3import { parseReqNsid, verifyJwt } from "@atproto/xrpc-server";
4import { supabaseServerClient } from "supabase/serverClient";
5import {
6 normalizeDocumentRecord,
7 type NormalizedDocument,
8} from "src/utils/normalizeRecords";
9
10const serviceDid = "did:web:leaflet.pub:lish:feeds";
11export async function GET(
12 req: Request,
13 { params }: { params: Promise<{ path: string[] }> },
14) {
15 let { path } = await params;
16 if (path[0] === "did.json")
17 return NextResponse.json({
18 "@context": ["https://www.w3.org/ns/did/v1"],
19 id: serviceDid,
20 service: [
21 {
22 id: "#bsky_fg",
23 type: "BskyFeedGenerator",
24 serviceEndpoint: `https://leaflet.pub/lish/feeds`,
25 },
26 ],
27 });
28 let auth = validateAuth(req, serviceDid);
29 if (!auth) return NextResponse.json({}, { status: 301 });
30 let { data: publications } = await supabaseServerClient
31 .from("publication_subscriptions")
32 .select(`publications(documents_in_publications(documents(*)))`)
33 .eq("identity", auth);
34 return NextResponse.json({
35 feed: [
36 ...(publications || []).flatMap((pub) => {
37 let posts = pub.publications?.documents_in_publications || [];
38 return posts.flatMap((p) => {
39 if (!p.documents?.data) return [];
40 const normalizedDoc = normalizeDocumentRecord(p.documents.data, p.documents.uri);
41 if (!normalizedDoc?.bskyPostRef) return [];
42 return { post: normalizedDoc.bskyPostRef.uri };
43 });
44 }),
45 ],
46 });
47}
48
49const didResolver = new DidResolver({});
50const validateAuth = async (
51 req: Request,
52 serviceDid: string,
53): Promise<string | null> => {
54 const authorization = req.headers.get("authorization");
55 if (!authorization?.startsWith("Bearer ")) {
56 return null;
57 }
58 const jwt = authorization.replace("Bearer ", "").trim();
59 const nsid = parseReqNsid(req);
60 const parsed = await verifyJwt(jwt, serviceDid, nsid, async (did: string) => {
61 return didResolver.resolveAtprotoKey(did);
62 });
63 return parsed.iss;
64};